4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
15 // PARSER.C -- parsing routines
18 // This module contains the NMAKE grammar parser. It parses input and uses the
19 // getToken() routine to get the next token.
28 // macros that deal w/ the productions stack and the actions function table
30 #define topStack() (stack[top])
31 #define popStackAndReturn() (stack[top--])
32 #define popStack() top--
33 #define pushStack(A) (stack[++top] = A)
34 #define doAction(A) (*(actions[A & LOW_NIBBLE]))()
38 // parse() table-driven parser for makefile grammar
40 // arguments: init global boolean value -- TRUE if tools.ini is the
43 // actions: initializes the stack (by pushing the empty-stack symbol
44 // and the start symbol)
45 // keeps track of current line (because the lexer may have
46 // read '\n' as a delimiter, and will thus be one line
47 // ahead of the parser)
48 // while the stack is not empty
49 // if the top symbol on the stack is an action
50 // do the action, popping the stack
51 // if the symbol on top of the stack now is a token
52 // if it's not the token we're expecting
55 // pop token off the stack
56 // if the top symbol on the stack is an action
57 // do the action, popping the stack
58 // reset curent line to lexer's current line
59 // get another token (use the lookahead token
60 // if it exists, and if it had caused the
61 // lexer's line count to be incremented,
62 // decrement our local count because we're
63 // still parsing the preceding line)
64 // else the symbol on top of the stack is a production
65 // find next production to do in production table
66 // (based on current input token and current
67 // production on stack)
68 // if the table entry is an error condition
69 // print appropriate error message, halt
70 // pop current production off stack
71 // if the "next production" can be one of two
72 // things, decide which one to use by peeking
73 // at the next input token and looking in the
74 // "useAlternate" decision table (using the last
75 // production and next input token as indexes)
76 // if the appropriate table entry is YES,
77 // use the next larger production from the one
78 // we found in the production table
79 // push each symbol in the production on the stack
82 // modifies: stack production stack, static to this module
83 // top index of current symbol at top of stack
85 // Use extreme care in modifying this code or any of the tables associated
86 // with it. The methods used to build the tables are described in detail
87 // in grammar.h and table.h. This parser is based on the predictive parser
88 // described on pages 186-191 of Aho & Ullman "Principles of Compiler Design."
89 // I have modified it to use an extra symbol of lookahead to deal w/ an
90 // ambiguous grammar and have added code to perform appropriate actions as
91 // it parses the productions.
96 UCHAR stackTop
, token
, nextToken
= 0;
97 register unsigned n
, i
;
99 firstToken
= TRUE
; // global var
100 pushStack(ACCEPT
); // init stack
103 token
= getToken(MAXBUF
,START
); // get first token
104 while ((stackTop
= topStack()) != ACCEPT
) {
105 if (ON(stackTop
,ACTION_MASK
)) {
106 doAction(popStackAndReturn());
107 } else if (ON(stackTop
,TOKEN_MASK
)) {
108 if (stackTop
!= token
) {
109 makeError(currentLine
,SYNTAX
+FATAL_ERR
,buf
);
113 printf ("DEBUG: parse 1: %d\n", line
);
115 if (ON(topStack(),ACTION_MASK
)) {
116 doAction(popStackAndReturn());
119 printf ("DEBUG: parse 2: %d\n", line
);
122 if (nextToken
) { // if we already
123 if (*buf
== '\n') --currentLine
; // have a token,
124 token
= nextToken
; // use it . . .
127 token
= getToken(MAXBUF
,topStack());
132 n
= table
[stackTop
][token
& LOW_NIBBLE
];
134 printf ("DEBUG: parse 3: %x %d %x %x\n", n
, stackTop
, token
& LOW_NIBBLE
, token
);
136 if (ON(n
,ERROR_MASK
)) {
138 printf ("DEBUG: parse 4: %d %s\n", line
, buf
);
140 makeError(currentLine
,n
+FATAL_ERR
,buf
);
143 if (ON(n
,AMBIG_MASK
)) { // 2 possible prod
144 n
&= LOW_NIBBLE
; // only use 4 bits
145 if (!nextToken
) { // peek to decide
146 nextToken
= getToken(MAXBUF
,stackTop
);
148 n
+= (useAlternate
[stackTop
][nextToken
& LOW_NIBBLE
]);
150 for (i
= productions
[n
][0]; i
; --i
) { // put production
151 pushStack(productions
[n
][i
]); // on stack
155 popStack(); // pop the ACCEPT off the stack